/**********************************************
 * Id:  A31C081D-C543-4A5D-9128-E5677B257C8F
 * Author :  levinknight
 * Creation Time: 2009-05-19 10:25:14
 * Description: 
 **********************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Synchronization.Data;

namespace SyncEngine.Data
{
    /// <summary>
    /// Sync Configuration
    /// </summary>
    [Serializable]
    public class SyncConfig
    {
        #region Fields

        private readonly XElement _documentRoot;

        #endregion

        #region Constructor(s) && Dispose

        public SyncConfig()
        {
            
        }

        public SyncConfig(string configFilePath)
        {
            _documentRoot = XElement.Load(configFilePath);
            InitializeConfig();
        }

        #endregion

        #region Public Method(s)

        #endregion

        #region Private Method(s)

        private void InitializeConfig()
        {
            ConnectionString = GetConnectionString();
            SelectNewAnchorCommandText = GetSelectNewAnchorCommandText();
            BeforeSyncExecuteCommands = GetBeforeSyncExecuteCommands();
            AfterSyncExecuteCommands = GetAfterSyncExecuteCommands();
            SyncTableConfigs = GetSyncTableConfigs();
        }

        private string GetConnectionString()
        {
            return GetSingleValueFromElement("ConnectionString");
        }

        private string GetSelectNewAnchorCommandText()
        {
            return GetSingleValueFromElement("SelectNewAnchorCommandText");
        }

        private string GetSingleValueFromElement(string elementname)
        {
            XElement databaseTypeElement = _documentRoot.Element(elementname);
            if (databaseTypeElement != null)
                return databaseTypeElement.Value;
            return string.Empty; 
        }

        private List<SQLCommand> GetBeforeSyncExecuteCommands()
        {
            return GetSQLCommands(_documentRoot.Element("BeforeSyncExecuteCommand"));
        }

        private List<SQLCommand> GetAfterSyncExecuteCommands()
        {
            return GetSQLCommands(_documentRoot.Element("AfterSyncExecuteCommand"));
        }

        private static List<SQLCommand> GetSQLCommands(XElement executeCommandElement)
        {
            List<SQLCommand> commands = new List<SQLCommand>();
            if (executeCommandElement != null && executeCommandElement.Elements().Count() > 0)
            {
                var query = from t in executeCommandElement.Elements("SQLCommand")
                            select t;

                foreach (XElement element in query)
                {
                    SQLCommand command = new SQLCommand();
                    
                    XAttribute enableAttribute = element.Attribute("Enable");
                    if (enableAttribute != null)
                    {
                        bool enable;
                        bool.TryParse(enableAttribute.Value, out enable);
                        command.Enable = enable;
                    }

                    XAttribute timeAttribute = element.Attribute("Time");
                    if (timeAttribute != null)
                    {
                        DateTime time;
                        DateTime.TryParse(timeAttribute.Value, out time);
                        command.Time = time;
                    }

                    XAttribute descriptionAttribute = element.Attribute("Description");
                    if (descriptionAttribute != null)
                    {
                        command.Description = descriptionAttribute.Value;
                    }

                    command.CommandText = element.Value;

                    commands.Add(command);
                }
            }

            return commands;
        }

        private List<SyncTableConfig> GetSyncTableConfigs()
        {
            List<SyncTableConfig> syncTableConfigs = new List<SyncTableConfig>();
           
            XElement syncTableElement = _documentRoot.Element("SyncTable");
           
            if (syncTableElement != null && syncTableElement.Elements().Count() > 0)
            {
                var query = from t in syncTableElement.Elements()
                            select t;
                foreach (XElement element in query)
                {
                    SyncTableConfig config = new SyncTableConfig { TableName = element.Name.LocalName };

                    XAttribute enableAttribute = element.Attribute("Enable");
                    if (enableAttribute != null)
                    {
                        bool enable;
                        bool.TryParse(enableAttribute.Value, out enable);
                        config.Enable = enable;
                    }

                    XAttribute syncGroupAttribute = element.Attribute("SyncGroup");
                    if (syncGroupAttribute != null)
                    {
                        config.SyncGroup = !string.IsNullOrEmpty(syncGroupAttribute.Value) ?
                            new SyncGroup(syncGroupAttribute.Value) : 
                            new SyncGroup(element.Name.LocalName);
                    }
                    else
                    {
                        config.SyncGroup = new SyncGroup(element.Name.LocalName);
                    }

                    XAttribute syncDirectionAttribute = element.Attribute("SyncDirection");
                    if (syncDirectionAttribute != null)
                    {
                        SyncDirection syncDirection = SyncDirection.DownloadOnly;

                        if (!string.IsNullOrEmpty(syncDirectionAttribute.Value))
                        {
                            object optionObject = Enum.Parse(typeof(SyncDirection), syncDirectionAttribute.Value, true);

                            if (optionObject != null)
                            {
                                syncDirection = (SyncDirection)optionObject;
                            }
                        }

                        config.SyncDirection = syncDirection;
                    }
                    else
                    {
                        config.SyncDirection = SyncDirection.DownloadOnly;
                    }

                    XAttribute tableCreationOptionAttribute = element.Attribute("TableCreationOption");
                    if (tableCreationOptionAttribute != null)
                    {
                        TableCreationOption tableCreationOption = TableCreationOption.UseExistingTableOrFail;

                        if (!string.IsNullOrEmpty(tableCreationOptionAttribute.Value))
                        {
                            object optionObject = Enum.Parse(typeof(TableCreationOption), tableCreationOptionAttribute.Value, true);

                            if (optionObject != null)
                            {
                                tableCreationOption = (TableCreationOption)optionObject;
                            }
                        }

                        config.TableCreationOption = tableCreationOption;
                    }
                    else
                    {
                        config.TableCreationOption = TableCreationOption.UseExistingTableOrFail;
                    }

                    XAttribute descriptionAttribute = element.Attribute("Description");
                    if (descriptionAttribute != null)
                    {
                        config.Description = descriptionAttribute.Value;
                    }

                    XElement selectIncrementalInsertsCommandTextElement = element.Element("SelectIncrementalInsertsCommandText");
                    if (selectIncrementalInsertsCommandTextElement != null)
                        config.SelectIncrementalInsertsCommandText = selectIncrementalInsertsCommandTextElement.Value;

                    XElement selectIncrementalDeletesCommandTextElement = element.Element("SelectIncrementalDeletesCommandText");
                    if (selectIncrementalDeletesCommandTextElement != null)
                        config.SelectIncrementalDeletesCommandText = selectIncrementalDeletesCommandTextElement.Value;

                    XElement selectIncrementalUpdatesCommandTextElement = element.Element("SelectIncrementalUpdatesCommandText");
                    if (selectIncrementalUpdatesCommandTextElement != null)
                        config.SelectIncrementalUpdatesCommandText = selectIncrementalUpdatesCommandTextElement.Value;

                    config.BeforeSyncExecuteCommands = GetSQLCommands(element.Element("BeforeSyncExecuteCommand"));
                    config.AfterSyncExecuteCommands = GetSQLCommands(element.Element("AfterSyncExecuteCommands"));

                    syncTableConfigs.Add(config);
                }
            }

            return syncTableConfigs;
        }

        #endregion

        #region Properties

        public string ConnectionString { get; set; }
        public string SelectNewAnchorCommandText { get; set; }
        public List<SQLCommand> BeforeSyncExecuteCommands { get; set; }
        public List<SQLCommand> AfterSyncExecuteCommands { get; set; }
        public List<SyncTableConfig> SyncTableConfigs { get; set; }

        #endregion

    }

    [Serializable]
    public class SQLCommand
    {
        public bool Enable { get; set; }
        public DateTime Time { get; set; }
        public string Description { get; set; }
        public string CommandText { get; set; }
    }

    [Serializable]
    public class SyncTableConfig
    {
        public bool Enable { get; set; }
        public string TableName { get; set; }
        public SyncGroup SyncGroup { get; set; }
        public SyncDirection SyncDirection { get; set; }
        public TableCreationOption TableCreationOption { get; set; }
        public string Description { get; set; }
        public string SelectIncrementalInsertsCommandText { get; set; }
        public string SelectIncrementalDeletesCommandText { get; set; }
        public string SelectIncrementalUpdatesCommandText { get; set; }
        public List<SQLCommand> BeforeSyncExecuteCommands { get; set; }
        public List<SQLCommand> AfterSyncExecuteCommands { get; set; }
    }
}